package model

import (
	"fmt"
	"smart-health-platforms/config"
	"time"
)

type SignRecord struct {
	Id        uint      `gorm:"column:id;type:bigint UNSIGNED;comment:主键;primaryKey;not null;" json:"id"`        // 主键
	UserId    uint      `gorm:"column:user_id;type:bigint;comment:用户id;not null;" json:"user_id"`                // 用户id
	SignDate  time.Time `gorm:"column:sign_date;type:datetime(3);comment:当天得到积分：可配置;not null;" json:"sign_date"` // 当天得到积分：可配置
	Points    uint      `gorm:"column:points;type:int;comment:当天得到积分：可配置;not null;" json:"points"`               // 当天得到积分：可配置
	CreatedAt time.Time `gorm:"column:created_at;type:datetime(3);not null;default:CURRENT_TIMESTAMP(3);" json:"created_at"`
}

func (sr *SignRecord) TableName() string {
	return "sign_record"
}

// 插入一条签到记录
func (sr *SignRecord) CreateRecord() error {
	return config.DB.Create(&sr).Error
}

// 根据用户ID获取签到列表
func (sr *SignRecord) GetSignListByUserID(userID int64, offset int, limit int) ([]SignRecord, int64, error) {
	var list []SignRecord
	var total int64
	// 先统计总数
	config.DB.Model(&SignRecord{}).Where("user_id = ?", userID).Count(&total)
	// 再查询分页数据
	err := config.DB.Where("user_id = ?", userID).
		Order("sign_date DESC").
		Offset(offset).
		Limit(limit).
		Find(&list).Error

	return list, total, err
}

// 判断当前用户（sr.UserId）在指定日期（sr.SignDate）是否已签到
func (sr *SignRecord) CheckDateExists() (bool, error) {
	var count int64
	err := config.DB.Model(&SignRecord{}).
		Where("user_id = ? AND sign_date = ?", sr.UserId, sr.SignDate).
		Count(&count).Error
	return count > 0, err
}

// 计算当前用户（sr.UserId）连续签到天数
func (sr *SignRecord) GetContinuousDays() (int32, error) {
	var list []SignRecord

	// 倒序取全部签到记录
	err := config.DB.Where("user_id = ?", sr.UserId).
		Order("sign_date DESC").
		Find(&list).Error
	if err != nil {
		return 0, err
	}

	continuous := int32(0) // 连续签到天数
	today := time.Now()

	for _, v := range list {
		expect := today.AddDate(0, 0, -int(continuous))                     // 计算期望的签到日期
		if v.SignDate.Format("2006-01-02") == expect.Format("2006-01-02") { // 签到日期与期望日期匹配
			continuous++
		} else {
			break
		}
	}
	return continuous, nil
}

// bitmapKey 生成：sign:bitmap:{userID}:{yyyyMM}
func (sr *SignRecord) bitmapKey(t time.Time) string {
	return fmt.Sprintf("sign:bitmap:%d:%s", sr.UserId, t.Format("200601"))
}

// 把今天标记为已签到（位图）
func (sr *SignRecord) MarkTodayBitmap() error {
	today := time.Now()
	key := sr.bitmapKey(today)
	offset := int64(today.Day() - 1)
	return config.Rdb.SetBit(config.Ctx, key, offset, 1).Err()
}

// 判断今天是否已签到（位图）
func (sr *SignRecord) IsTodayBitmapSigned() (bool, error) {
	today := time.Now()
	key := sr.bitmapKey(today)
	offset := int64(today.Day() - 1)
	val, err := config.Rdb.GetBit(config.Ctx, key, offset).Result()
	return val == 1, err
}

// 本月连续签到天数（位图）
func (sr *SignRecord) ContinuousDaysBitmap() (int, error) {
	today := time.Now()
	key := sr.bitmapKey(today)
	bits, err := config.Rdb.Get(config.Ctx, key).Bytes()
	if err != nil {
		return 0, err
	}
	days := today.Day()
	continuous := 0                  // 连续签到天数
	for i := days - 1; i >= 0; i-- { // 从今天开始往前遍历
		if len(bits) > i/8 && (bits[i/8]&(1<<(i%8))) != 0 {
			continuous++
		} else {
			break
		}
	}
	return continuous, nil
}
